package org.iabako.client.ui.form.user.customfield;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.HTMLPanel;
import org.iabako.client.config.page.PageConfigEnum;
import org.iabako.client.tools.IabakoAsyncCallback;
import org.iabako.client.tools.Messages;
import org.iabako.client.ui.form.AbstractForm;
import org.iabako.client.ui.layout.field.IField;
import org.iabako.client.ui.layout.field.LabelText;
import org.iabako.client.ui.layout.template.Popup;
import org.iabako.client.ui.layout.widget.validation.ValidationMessage;
import org.iabako.client.user.AuthenticateUserProvider;
import org.iabako.shared.entity.business.AbstractEntity;
import org.iabako.shared.entity.business.CustomField;
import org.iabako.shared.entity.enumeration.CustomFieldType;
import org.iabako.shared.exception.IabakoActionForbiddenException;
import org.iabako.shared.iservice.business.CustomFieldServiceAsync;
import org.iabako.shared.tools.GenericTools;

import java.util.*;

/**
 * Created by jose on 19/09/14.
 */
public abstract class ClientCustomFieldsConfigurationForm extends AbstractForm {

    interface MyUiBinder extends UiBinder<HTMLPanel, ClientCustomFieldsConfigurationForm> {
    }

    protected MyUiBinder binderForm = GWT.create(MyUiBinder.class);

    protected final CustomFieldServiceAsync customFieldServiceAsync = CustomFieldServiceAsync.Util.getInstance();

    @UiField
    HTMLPanel customFieldsPanel;
    @UiField
    LabelText newClientCustomFieldAction;
    @UiField
    HTMLPanel waitCustomFieldsPanel;

    Map<CustomField, CustomFieldForm> customFields = new LinkedHashMap<CustomField, CustomFieldForm>();
    Map<CustomField, List<String>> customFieldListItemAdded = new HashMap<CustomField, List<String>>();
    Map<CustomField, List<String>> customFieldListItemDeleted = new HashMap<CustomField, List<String>>();

    public ClientCustomFieldsConfigurationForm(PageConfigEnum accountConfiguration, String explanationLabel) throws IabakoActionForbiddenException {
        if (AuthenticateUserProvider.getUser().getEnterprise().isDemo()) {
            throw new IabakoActionForbiddenException("action_disable_for_demo_title", "action_disable_for_demo_text", true);
        }

        setForm(binderForm, accountConfiguration, explanationLabel);

        customFieldServiceAsync.getCustomFields(new CustomFieldsAsyncCallback(this));

        newClientCustomFieldAction.getLabel().addClickHandler(new AddCustomFieldHandler(this));

        Popup.resizeToMediumPopup();
    }

    class AddCustomFieldHandler implements ClickHandler {
        ClientCustomFieldsConfigurationForm parent;

        AddCustomFieldHandler(ClientCustomFieldsConfigurationForm parent) {
            this.parent = parent;
        }

        public void onClick(ClickEvent event) {
            if (customFields.size() >= AuthenticateUserProvider.getUser().getUserCredit().getIabakoPackage().getCustomFieldLimit()) {
                return;
            }
            CustomField customField = new CustomField();
            customField.setPosition(parent.getCustomFields().size());
            CustomFieldForm customFieldForm = new CustomFieldForm(parent, customField);

            addCustomFieldForm(customField, customFieldForm);
        }
    }

    class CustomFieldsAsyncCallback extends IabakoAsyncCallback<List<CustomField>> {
        ClientCustomFieldsConfigurationForm parent;

        CustomFieldsAsyncCallback(ClientCustomFieldsConfigurationForm parent) {
            this.parent = parent;
        }

        public void onSuccess(List<CustomField> result) {
            for (CustomField field : result) {
                CustomFieldForm customFieldForm = new CustomFieldForm(parent, field);

                addCustomFieldForm(field, customFieldForm);
            }

            waitCustomFieldsPanel.setVisible(false);
            checkNewCustomFieldEnabled();

            super.onSuccess(result);
        }
    }

    public void addCustomFieldForm(CustomField field, CustomFieldForm customFieldForm) {
        customFields.put(field, customFieldForm);
        customFieldsPanel.add(customFieldForm);
        checkArrowsVisibility();
        checkNewCustomFieldEnabled();
    }

    public void removeCustomFieldForm(CustomFieldForm customFieldForm) {
        customFields.remove(customFieldForm.getCustomField());
        customFieldsPanel.remove(customFieldForm);

        checkArrowsVisibility();
        checkLabelNumbers();
        checkNewCustomFieldEnabled();
    }

    private void checkNewCustomFieldEnabled() {
        newClientCustomFieldAction.setVisible(customFields.size() < AuthenticateUserProvider.getUser().getUserCredit().getIabakoPackage().getCustomFieldLimit());
    }

    private void checkLabelNumbers() {
        int i = 0;
        for (CustomFieldForm form : customFields.values()) {
            form.legend.setInnerText(Messages.getLabel("customfield_configuration_title", (i + 1) + ""));
            form.getCustomField().setPosition(i++);
        }
    }

    private void checkArrowsVisibility() {
        for (CustomFieldForm form : customFields.values()) {
            boolean isFirstOne = new ArrayList(customFields.values()).indexOf(form) == 0;
            boolean isLastOne = new ArrayList(customFields.values()).indexOf(form) == customFields.size() - 1;

            form.setArrowUpVisible(!isFirstOne);
            form.setArrowDownVisible(!isLastOne);
        }
    }

    public Map<CustomField, CustomFieldForm> getCustomFields() {
        return customFields;
    }

    public Map<CustomField, List<String>> getCustomFieldListItemDeleted() {
        return customFieldListItemDeleted;
    }

    public Map<CustomField, List<String>> getCustomFieldListItemAdded() {
        return customFieldListItemAdded;
    }

    @Override
    protected List<IField> getMandatoryFields() {
        return null;
    }

    @Override
    protected AbstractEntity getEntity() {
        return null;
    }

    @Override
    public boolean validate() {

        messages.getElement().scrollIntoView();

        ValidationMessage validationMessage = ValidationMessage.getFirstFromDOM();
        int i = 1;
        List<String> mandatoryErrors = new ArrayList<String>();
        for (CustomFieldForm customFieldForm : customFields.values()) {
            if (GenericTools.isEmpty(customFieldForm.title.getValue()) || GenericTools.isEmpty(customFieldForm.type.getEnumValue())) {
                mandatoryErrors.add(Messages.getLabel("custom_field_config_mandatory_error", i + ""));
            }
            i++;
        }
        validationMessage.showErrorMessage(true, true, mandatoryErrors.toArray(new String[mandatoryErrors.size()]));

        if (!mandatoryErrors.isEmpty()) {
            return false;
        }

        for (CustomField customField : customFields.keySet()) {
            CustomFieldForm customFieldForm = customFields.get(customField);
            customField.setTitle(customFieldForm.title.getValue());
            customField.setCriteriaSearch(customFieldForm.criteriaSearch.getValue());
            if (customField.getId() == null) {
                customField.setCustomFieldType((CustomFieldType) customFieldForm.type.getEnumValue());
            }
        }

        final List<CustomField> fields = new ArrayList<CustomField>(getCustomFields().keySet());
        Map<CustomField, List<String>> listItemAdded = getCustomFieldListItemAdded();
        Map<CustomField, List<String>> listItemDeleted = getCustomFieldListItemDeleted();
        customFieldServiceAsync.saveCustomFields(fields, listItemAdded, listItemDeleted, new IabakoAsyncCallback<Void>() {
            public void onSuccess(Void result) {
                popup.handleClickClose();
                ValidationMessage validationMessageInPageContent = ValidationMessage.getFromRootPage();
                validationMessageInPageContent.showSuccessMessage("validation_account_configuration_form_success");

                AuthenticateUserProvider.getUser().getEnterprise().setCustomFields(fields);

                super.onSuccess(result);
            }
        });
        return true;
    }

    public void moveUp(CustomField customField) {
        List<CustomField> keyList = new ArrayList<CustomField>(customFields.keySet());
        int newIndex = keyList.indexOf(customField) - 1;
        if (newIndex < 0) {
            return;
        }
        Map<CustomField, CustomFieldForm> oldCustomFields = new LinkedHashMap<CustomField, CustomFieldForm>();
        for (CustomField field : customFields.keySet()) {
            oldCustomFields.put(field, customFields.get(field));
        }
        customFields.clear();
        keyList.remove(customField);
        keyList.add(newIndex, customField);

        for (CustomField field : keyList) {
            customFields.put(field, oldCustomFields.get(field));
        }

        if (newIndex == 0) {
            customFieldsPanel.getElement().insertFirst(customFields.get(customField).getElement());
        } else {
            customFieldsPanel.getElement().insertAfter(customFields.get(customField).getElement(), customFields.get(keyList.get(newIndex - 1)).getElement());
        }

        checkArrowsVisibility();
        checkLabelNumbers();
    }

    public void moveDown(CustomField customField) {
        List<CustomField> keyList = new ArrayList<CustomField>(customFields.keySet());
        int newIndex = keyList.indexOf(customField) + 1;
        if (newIndex >= customFields.size()) {
            return;
        }
        Map<CustomField, CustomFieldForm> oldCustomFields = new LinkedHashMap<CustomField, CustomFieldForm>();
        for (CustomField field : customFields.keySet()) {
            oldCustomFields.put(field, customFields.get(field));
        }
        customFields.clear();
        keyList.remove(customField);
        keyList.add(newIndex, customField);

        for (CustomField field : keyList) {
            customFields.put(field, oldCustomFields.get(field));
        }

        customFieldsPanel.getElement().insertAfter(customFields.get(customField).getElement(), customFields.get(keyList.get(newIndex - 1)).getElement());

        checkArrowsVisibility();
        checkLabelNumbers();
    }
}
